#ifndef CONFIGUREINFO_H
#define CONFIGUREINFO_H

/*
 * pur @配置文件信息获取类，
 *      1、读取指定目录下以.conf结尾的配置文件
 *      2、配置项可以以\结尾代表连接下一行，
 *      3、以#开头代表注释
 *      4、以=区分key和value
 *      5、过滤行开头和结束的空白字符
 *      6、过滤分隔符=左右相连的空白字符
 *      7、过滤空白行
 *      8、可通过AddAutoReloadFile设置需要自动加载最新配置的文件
 *      9、通过StartAutoReload启动自动更新配置文件并设置更新周期
 *      10、通过SetDefaultValue设置配置文件中key的默认参数
 * author @ haibin.wang
 * date  @ 2013.10.10
 *
 * 不足：
 *  1、调用获取数值函数当key不存在的时候会返回0值或固定的赋值
 *
 * 用法：
 *  std::string errInfo;
 *  SingleConfig::SetConfigPath(filePath,errInfo);
 *  SingleConfig::SetDefaultValue(modulename, key, value);//设置key的默认值为value
 *  SingleConfig::AddAutoReloadFile(filePath); //设置自动监测变化配置文件
 *  SingleConfig::StartAutoReload(30); //设置30秒监测一次配置文件是否有变化
 *
 *  //获取变量值
 *  SingleConfig::GetStrValue(modulename, key);//获取字符数据
 *  SingleConfig::GetIntValue(modulename, key);//获取整型数据
 *  SingleConfig::GetDoubleValue(modulename, key);//获取double型数据
 *  SingleConfig::GetLongValue(modulename, key);//获取long或long long型数据
 *  SingleConfig::GetBoolValue(modulename, key);//获取bool型数据
 *
 * modifier @ haibin.wang, 2014.04.13
 *            增加自动加载配置文件
 *            增加设置默认参数
 */

#include <map>
#include <string>
#include <vector>

class ConfigureInfo {
    public:
    explicit ConfigureInfo();
    ~ConfigureInfo();

    /*
     * pur @ 读取指定目录下的所有config文件，不递归读取
     * para @ dir 指定读取的目录
     * para @ bChild 是否递归读取
     * para @ err 获取错误信息
     * return @ true 读取成功，false 读取失败
     */
    bool ReadConfigue(const char *dir, bool bChild, std::string &err);

    /* pur @ 读取指定配置文件内容
     * para @ configFile 要读取的配置文件全路径
     * para @ err 获取错误信息
     * return @ true 读取成功，false 读取失败
    */
    bool ReadConfigue(const char *configFile, std::string &err);

    /* pur @ 设置默认配置参数
     * para @ filename 配置文件名,不能为NULL
     * para @ key 配置项的key, 不能为NULL
     * para @ defValue 默认的value值
     * return @ true设置成功，false 设置失败，filename或key为NULL
     */
    bool SetDefaultValue(const char *filename, const char *key, const char *defValue);
    bool SetDefaultValue(const char *filename, const char *key, const int &defValue);
    bool SetDefaultValue(const char *filename, const char *key, const long long &defValue);
    bool SetDefaultValue(const char *filename, const char *key, const double &defValue);

    /*
     * pur @ 根据模块名和key获取value
     * para @ modulename 配置文件名带后缀名
     * para @ key 要读取的key值
     * return @ 返回读取的字符串value值，空说明没有相关配置项
     */
    std::string GetStrValue(const char *modulename, const char *key);

    /*
     * pur @ 根据模块名和key获取value
     * para @ modulename 配置文件名带后缀名
     * para @ key 要读取的key值
     * return @ 返回读取的数字value值，-65536说明没读取到
     */
    int GetIntValue(const char *modulename, const char *key);

    /*
     * pur @ 根据模块名和key获取value,,如果key不存在会返回0.0
     * para @ modulename 配置文件名带后缀名
     * para @ key 要读取的key值
     * return @ 返回读取的数字value值
     */
    double GetDoubleValue(const char *modulename, const char *key);

    /*
     * pur @ 根据模块名和key获取value，如果key不存在会返回0
     * para @ modulename 配置文件名带后缀名
     * para @ key 要读取的key值
     * return @ 返回读取的数字value值
     */
    long long GetLongValue(const char *modulename, const char *key);

    /*
     * pur @ 根据模块名和key获取value
     * para @ modulename 配置文件名带后缀名
     * para @ key 要读取的key值
     * return @ 返回读取的bool型的value值，读取到1返回true，其他值为false;
     */
    bool GetBoolValue(const char *modulename, const char *key);

    /*
     * pur @重新加载指定的配置文件
     * para @ filename 配置文件全路径包含文件名
     * return @ 是否加载成功
     */
    bool ReloadOne(const char *filepath);

    /* pur @ 添加自动定时重新加载的配置文件
     * para @ filepath 配置文件全路径包含文件名
     * return @
    */
    void AddAutoReloadFile(const std::string &filepath);

    /* pur @ 启动自动定时重新加载配置文件
     * para @ checkInter 自动检测配置文件变化的时间间隔,
     *          单位：秒，必须大于等于1，否则不会启动自动更新配置文件功能
    */
    void StartAutoReload(const int &checkInter);

    public: //以下为线程使用函数
            /* pur @ 获取自动加载配置文件列表
             * return @  返回所有设置的需要自动加载配置文件的列表
            */
    std::vector<std::string> &GetAutoReloadFiles();

    /* pur @ 获取自动加载配置文件的时间间隔
     * return @  返回时间间隔
    */
    int GetAutoReloadInter();

    /* pur @ 获取自动检测状态
     * return @ true 正在监测，false，停止
    */
    bool GetStopCheckState();

    private:
    /* pur @ 根据文件路径获取文件的名字
     * para @ filepath 文件路径
     * para @
     * return @ 返回文件名否则返回空串
    */
    std::string GetFileName(const char *filepath);
    /*
     * pur @ 读取指定配置文件
     * para @ filename 指定读取的文件
     * para @ modulename 指定模块名，用于拼接模块和key
     * return @ true 读取成功，false 读取失败
     */
    void ReadFileInfo(const char *filename, const char *modulename);

    /*
     * pur @ 判定文件是否是是以conf结尾的文件
     */
    bool bConfigFile(const char *filename);

    /*
     * pur @ 去掉line前后空格和tab字符
     */
    void TrimLine(std::string &line);

    /*
     * pur @ 获取组合后的key名
     * para @ modulename 指定模块名，
     * para @ 配置项的key
     */
    std::string GetKeyName(const char *modulename, const char *key);

    /*
     * pur @ 插入key和value到列表中
     * para @ modulename 指定模块名，
     * para @ 配置项的key
     * para @ value 新的value值
     */
    void InsertValueToList(const char *modulename, const std::string &key, const std::string &value);

    /* pur @ 自动加载配置文件线程函数
     * return @
    */
    static void *AutoReladThread(void *);

    int m_autoCheckInter;      //自动检测配置文件变化时间间隔
    pthread_t m_checkThreadId; //自动检测线程id
    bool m_bStopCheck;         //是否停止自动检测
    bool m_bStartCheck;        //是否已经启动线程检测
    std::map<std::string, std::string> m_conf;              //存放所有配置信息
    std::map<std::string, pthread_mutex_t *> m_fileMutexes; //文件锁，key为文件名
    std::map<std::string, std::string> m_defStrValue;       //存放默认值配置信息
    std::vector<std::string> m_autoReloadModul;             //自动加载模块
};

#endif
